home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / FLTK-1.0.6 / src / Fl_Browser_.cxx < prev    next >
Encoding:
C/C++ Source or Header  |  1999-09-15  |  18.5 KB  |  670 lines

  1. //
  2. // "$Id: Fl_Browser_.cxx,v 1.10.2.3 1999/09/15 15:18:11 mike Exp $"
  3. //
  4. // Base Browser widget class for the Fast Light Tool Kit (FLTK).
  5. //
  6. // Copyright 1998-1999 by Bill Spitzak and others.
  7. //
  8. // This library is free software; you can redistribute it and/or
  9. // modify it under the terms of the GNU Library General Public
  10. // License as published by the Free Software Foundation; either
  11. // version 2 of the License, or (at your option) any later version.
  12. //
  13. // This library is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16. // Library General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Library General Public
  19. // License along with this library; if not, write to the Free Software
  20. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  21. // USA.
  22. //
  23. // Please report all bugs and problems to "fltk-bugs@easysw.com".
  24. //
  25.  
  26. #include <FL/Fl.H>
  27. #include <FL/Fl_Widget.H>
  28. #include <FL/Fl_Browser_.H>
  29. #include <FL/fl_draw.H>
  30.  
  31.  
  32. // This is the base class for browsers.  To be useful it must be
  33. // subclassed and several virtual functions defined.  The
  34. // Forms-compatable browser and the file chooser's browser are
  35. // subclassed off of this.
  36.  
  37. // Yes, I know this should be a template...
  38.  
  39. // This has been designed so that the subclass has complete control
  40. // over the storage of the data, although because next() and prev()
  41. // functions are used to index, it works best as a linked list or as a
  42. // large block of characters in which the line breaks must be searched
  43. // for.
  44.  
  45. // A great deal of work has been done so that the "height" of a data
  46. // object does not need to be determined until it is drawn.  This was
  47. // done for the file chooser, because the height requires doing stat()
  48. // to see if the file is a directory, which can be annoyingly slow
  49. // over the network.
  50.  
  51. /* redraw bits:
  52.    1 = redraw children (the scrollbar)
  53.    2 = redraw one or two items
  54.    4 = redraw all items
  55. */
  56.  
  57. static void scrollbar_callback(Fl_Widget* s, void*) {
  58.   ((Fl_Browser_*)(s->parent()))->position(int(((Fl_Scrollbar*)s)->value()));
  59. }
  60.  
  61. static void hscrollbar_callback(Fl_Widget* s, void*) {
  62.   ((Fl_Browser_*)(s->parent()))->hposition(int(((Fl_Scrollbar*)s)->value()));
  63. }
  64.  
  65. int Fl_Browser_::scrollbar_width_ = 17;
  66.  
  67. // return where to draw the actual box:
  68. void Fl_Browser_::bbox(int& X, int& Y, int& W, int& H) const {
  69.   Fl_Boxtype b = box() ? box() : FL_DOWN_BOX;
  70.   X = x()+Fl::box_dx(b);
  71.   Y = y()+Fl::box_dy(b);
  72.   W = w()-Fl::box_dw(b);
  73.   H = h()-Fl::box_dh(b);
  74.   if (scrollbar.visible()) {
  75.     W -= scrollbar_width_;
  76.     if (scrollbar.align() & FL_ALIGN_LEFT) X += scrollbar_width_;
  77.   }
  78.   if (hscrollbar.visible()) {
  79.     H -= scrollbar_width_;
  80.     if (scrollbar.align() & FL_ALIGN_TOP) Y += scrollbar_width_;
  81.   }
  82. }
  83.  
  84. int Fl_Browser_::leftedge() const {
  85.   int X, Y, W, H; bbox(X, Y, W, H);
  86.   return X;
  87. }
  88.  
  89. // the scrollbars are resized & placed by draw(), since each one's size
  90. // depends on whether the other is visible or not.  This skips over
  91. // Fl_Group::resize since it moves the scrollbars uselessly.
  92. void Fl_Browser_::resize(int X, int Y, int W, int H) {
  93.   Fl_Widget::resize(X, Y, W, H);
  94. }
  95.  
  96. // Cause minimal update to redraw the given item:
  97. void Fl_Browser_::redraw_line(void* l) {
  98.   if (!redraw1 || redraw1 == l) {redraw1 = l; damage(FL_DAMAGE_EXPOSE);}
  99.   else if (!redraw2 || redraw2 == l) {redraw2 = l; damage(FL_DAMAGE_EXPOSE);}
  100.   else damage(FL_DAMAGE_SCROLL);
  101. }
  102.  
  103. // Figure out top() based on position():
  104. void Fl_Browser_::update_top() {
  105.   if (!top_) top_ = item_first();
  106.   if (position_ != real_position_) {
  107.     void* l;
  108.     int ly;
  109.     int y = position_;
  110.     // start from either head or current position, whichever is closer:
  111.     if (!top_ || y <= (real_position_/2)) {
  112.       l = item_first();
  113.       ly = 0;
  114.     } else {
  115.       l = top_;
  116.       ly = real_position_-offset_;
  117.     }
  118.     if (!l) {
  119.       top_ = 0;
  120.       offset_ = 0;
  121.       real_position_ = 0;
  122.     } else {
  123.       int h = item_quick_height(l);
  124.       // step through list until we find line containing this point:
  125.       while (ly > y) {
  126.     void* l1 = item_prev(l);
  127.     if (!l1) {ly = 0; break;} // hit the top
  128.     l = l1;
  129.     h = item_quick_height(l);
  130.     ly -= h;
  131.       }
  132.       while ((ly+h) <= y) {
  133.     void* l1 = item_next(l);
  134.     if (!l1) {y = ly+h-1; break;}
  135.     l = l1;
  136.     ly += h;
  137.     h = item_quick_height(l);
  138.       }
  139.       // top item must *really* be visible, use slow height:
  140.       for (;;) {
  141.     h = item_height(l);
  142.     if ((ly+h) > y) break; // it is big enough to see
  143.     // go up to top of previous item:
  144.     void* l1 = item_prev(l);
  145.     if (!l1) {ly = y = 0; break;} // hit the top
  146.     l = l1; y = position_ = ly = ly-item_quick_height(l);
  147.       }
  148.       // use it:
  149.       top_ = l;
  150.       offset_ = y-ly;
  151.       real_position_ = y;
  152.     }
  153.     damage(FL_DAMAGE_SCROLL);
  154.   }
  155. }
  156.  
  157. // Change position(), top() will update when update_top() is called
  158. // (probably by draw() or handle()):
  159. void Fl_Browser_::position(int y) {
  160.   if (y < 0) y = 0;
  161.   if (y == position_) return;
  162.   position_ = y;
  163.   if (y != real_position_) redraw_lines();
  164. }
  165.  
  166. void Fl_Browser_::hposition(int x) {
  167.   if (x < 0) x = 0;
  168.   if (x == hposition_) return;
  169.   hposition_ = x;
  170.   if (x != real_hposition_) redraw_lines();
  171. }
  172.  
  173. // Tell whether item is currently displayed:
  174. int Fl_Browser_::displayed(void* x) const {
  175.   int X, Y, W, H; bbox(X, Y, W, H);
  176.   int yy = H+offset_;
  177.   for (void* l = top_; l && yy > 0; l = item_next(l)) {
  178.     if (l == x) return 1;
  179.     yy -= item_height(l);
  180.   }
  181.   return 0;
  182. }
  183.  
  184. // Insure this item is displayed:
  185. // Messy because we have no idea if it is before top or after bottom:
  186. void Fl_Browser_::display(void* x) {
  187.   update_top();
  188.   if (x == item_first()) {position(0); return;}
  189.   int X, Y, W, H; bbox(X, Y, W, H);
  190.   void* l = top_;
  191.   Y = -offset_;
  192.   // see if it is at the top or just above it:
  193.   if (l == x) {position(real_position_+Y); return;} // scroll up a bit
  194.   void* lp = item_prev(l);
  195.   if (lp == x) {position(real_position_+Y-item_quick_height(lp)); return;}
  196.   // search forward for it:
  197.   for (; l; l = item_next(l)) {
  198.     int h1 = item_quick_height(l);
  199.     if (l == x) {
  200.       if (Y <= H) { // it is visible or right at bottom
  201.     Y = Y+h1-H; // find where bottom edge is
  202.     if (Y > 0) position(real_position_+Y); // scroll down a bit
  203.       } else {
  204.     position(real_position_+Y-(H-h1)/2); // center it
  205.       }
  206.       return;
  207.     }
  208.     Y += h1;
  209.   }
  210.   // search backward for it, if found center it:
  211.   l = lp;
  212.   Y = -offset_;
  213.   for (; l; l = item_prev(l)) {
  214.     int h1 = item_quick_height(l);
  215.     Y -= h1;
  216.     if (l == x) {
  217.       if ((Y + h1) >= 0) position(real_position_+Y);
  218.       else position(real_position_+Y-(H-h1)/2);
  219.       return;
  220.     }
  221.   }
  222. }
  223.  
  224. // redraw, has side effect of updating top and setting scrollbar:
  225.  
  226. void Fl_Browser_::draw() {
  227.   int drawsquare = 0;
  228.   if (damage() & FL_DAMAGE_ALL) { // redraw the box if full redraw
  229.     Fl_Boxtype b = box() ? box() : FL_DOWN_BOX;
  230.     draw_box(b, x(), y(), w(), h(), color());
  231.     drawsquare = 1;
  232.   }
  233.  
  234.   update_top();
  235.   int full_width_ = full_width();
  236.   int full_height_ = full_height();
  237.   int X, Y, W, H; bbox(X, Y, W, H);
  238.   int dont_repeat = 0;
  239. J1:
  240.   // see if scrollbar needs to be switched on/off:
  241.   if ((has_scrollbar_ & VERTICAL) && (
  242.     (has_scrollbar_ & ALWAYS_ON) || position_ || full_height_ > H)) {
  243.     if (!scrollbar.visible()) {
  244.       scrollbar.set_visible();
  245.       drawsquare = 1;
  246.       bbox(X, Y, W, H);
  247.     }
  248.   } else {
  249.     top_ = item_first(); real_position_ = offset_ = 0;
  250.     if (scrollbar.visible()) {
  251.       scrollbar.clear_visible();
  252.       clear_damage(damage()|FL_DAMAGE_SCROLL);
  253.     }
  254.   }
  255.  
  256.   if ((has_scrollbar_ & HORIZONTAL) && (
  257.     (has_scrollbar_ & ALWAYS_ON) || hposition_ || full_width_ > W)) {
  258.     if (!hscrollbar.visible()) {
  259.       hscrollbar.set_visible();
  260.       drawsquare = 1;
  261.       bbox(X, Y, W, H);
  262.     }
  263.   } else {
  264.     real_hposition_ = 0;
  265.     if (hscrollbar.visible()) {
  266.       hscrollbar.clear_visible();
  267.       clear_damage(damage()|FL_DAMAGE_SCROLL);
  268.     }
  269.   }
  270.  
  271.   // Check the vertical scrollbar again, just in case it needs to be drawn
  272.   // because the horizontal one is drawn.  There should be a cleaner way
  273.   // to do this besides copying the same code...
  274.   if ((has_scrollbar_ & VERTICAL) && (
  275.     (has_scrollbar_ & ALWAYS_ON) || position_ || full_height_ > H)) {
  276.     if (!scrollbar.visible()) {
  277.       scrollbar.set_visible();
  278.       drawsquare = 1;
  279.       bbox(X, Y, W, H);
  280.     }
  281.   } else {
  282.     top_ = item_first(); real_position_ = offset_ = 0;
  283.     if (scrollbar.visible()) {
  284.       scrollbar.clear_visible();
  285.       clear_damage(damage()|FL_DAMAGE_SCROLL);
  286.     }
  287.   }
  288.  
  289.   bbox(X, Y, W, H);
  290.  
  291.   fl_clip(X, Y, W, H);
  292.   // for each line, draw it if full redraw or scrolled.  Erase background
  293.   // if not a full redraw or if it is selected:
  294.   void* l = top();
  295.   int yy = -offset_;
  296.   for (; l && yy < H; l = item_next(l)) {
  297.     int hh = item_height(l);
  298.     if (hh <= 0) continue;
  299.     if ((damage()&(FL_DAMAGE_SCROLL|FL_DAMAGE_ALL)) || l == redraw1 || l == redraw2) {
  300.       if (item_selected(l)) {
  301.     fl_color(selection_color());
  302.     fl_rectf(X, yy+Y, W, hh);
  303.       } else if (!(damage()&FL_DAMAGE_ALL)) {
  304.     fl_color(color());
  305.     fl_rectf(X, yy+Y, W, hh);
  306.       }
  307.       if (type() == FL_MULTI_BROWSER && l == selection_) {
  308.     fl_color(textcolor());
  309.     fl_rect(X+1, yy+Y, W-2, hh);
  310.       }
  311.       item_draw(l, X-hposition_, yy+Y, W+hposition_, hh);
  312.       int w = item_width(l);
  313.       if (w > max_width) {max_width = w; max_width_item = l;}
  314.     }
  315.     yy += hh;
  316.   }
  317.   // erase the area below last line:
  318.   if (!(damage()&FL_DAMAGE_ALL) && yy < H) {
  319.     fl_color(color());
  320.     fl_rectf(X, yy+Y, W, H-yy);
  321.   }
  322.   fl_pop_clip();
  323.   redraw1 = redraw2 = 0;
  324.  
  325.   if (!dont_repeat) {
  326.     dont_repeat = 1;
  327.     // see if changes to full_height caused by calls to slow_height
  328.     // caused scrollbar state to change, in which case we have to redraw:
  329.     full_height_ = full_height();
  330.     full_width_ = full_width();
  331.     if ((has_scrollbar_ & VERTICAL) &&
  332.     ((has_scrollbar_ & ALWAYS_ON) || position_ || full_height_>H)) {
  333.       if (!scrollbar.visible()) goto J1;
  334.     } else {
  335.       if (scrollbar.visible()) goto J1;
  336.     }
  337.     if ((has_scrollbar_ & HORIZONTAL) &&
  338.     ((has_scrollbar_ & ALWAYS_ON) || hposition_ || full_width_>W)) {
  339.       if (!hscrollbar.visible()) goto J1;
  340.     } else {
  341.       if (hscrollbar.visible()) goto J1;
  342.     }
  343.   }
  344.  
  345.   // update the scrollbars and redraw them:
  346.   int dy = top_ ? item_quick_height(top_) : 0; if (dy < 10) dy = 10;
  347.   if (scrollbar.visible()) {
  348.     scrollbar.damage_resize(
  349.     scrollbar.align()&FL_ALIGN_LEFT ? X-scrollbar_width_ : X+W,
  350.     Y, scrollbar_width_, H);
  351.     scrollbar.value(position_, H, 0, full_height_);
  352.     scrollbar.linesize(dy);
  353.     if (drawsquare) draw_child(scrollbar);
  354.     else update_child(scrollbar);
  355.   }
  356.   if (hscrollbar.visible()) {
  357.     hscrollbar.damage_resize(
  358.     X, scrollbar.align()&FL_ALIGN_TOP ? Y-scrollbar_width_ : Y+H,
  359.     W, scrollbar_width_);
  360.     hscrollbar.value(hposition_, W, 0, full_width_);
  361.     hscrollbar.linesize(dy);
  362.     if (drawsquare) draw_child(hscrollbar);
  363.     else update_child(hscrollbar);
  364.   }
  365.  
  366.   // draw that little square between the scrollbars:
  367.   if (drawsquare && scrollbar.visible() && hscrollbar.visible()) {
  368.     fl_color(parent()->color());
  369.     fl_rectf(scrollbar.x(), hscrollbar.y(), scrollbar_width_,scrollbar_width_);
  370.   }
  371.  
  372.   real_hposition_ = hposition_;
  373. }
  374.  
  375. // Quick way to delete and reset everything:
  376. void Fl_Browser_::new_list() {
  377.   top_ = 0;
  378.   position_ = real_position_ = 0;
  379.   hposition_ = real_hposition_ = 0;
  380.   selection_ = 0;
  381.   offset_ = 0;
  382.   max_width = 0;
  383.   max_width_item = 0;
  384.   redraw_lines();
  385. }
  386.  
  387. // Tell it that this item is going away, and that this must remove
  388. // all pointers to it:
  389. void Fl_Browser_::deleting(void* l) {
  390.   if (displayed(l)) redraw_lines();
  391.   if (l == selection_) selection_ = 0;
  392.   if (l == top_) {
  393.     real_position_ -= offset_;
  394.     offset_ = 0;
  395.     top_ = item_next(l);
  396.     if (!top_) top_ = item_prev(l);
  397.   }
  398.   if (l == max_width_item) {max_width_item = 0; max_width = 0;}
  399. }
  400.  
  401. void Fl_Browser_::replacing(void* a, void* b) {
  402.   redraw_line(a);
  403.   if (a == selection_) selection_ = b;
  404.   if (a == top_) top_ = b;
  405.   if (a == max_width_item) {max_width_item = 0; max_width = 0;}
  406. }
  407.  
  408. void Fl_Browser_::inserting(void* a, void* b) {
  409.   if (displayed(a)) redraw_lines();
  410.   if (a == top_) top_ = b;
  411. }
  412.  
  413. void* Fl_Browser_::find_item(int my) {
  414.   update_top();
  415.   int X, Y, W, H; bbox(X, Y, W, H);
  416.   void* l;
  417.   int yy = Y-offset_;
  418.   for (l = top_; l; l = item_next(l)) {
  419.     int hh = item_height(l); if (hh <= 0) continue;
  420.     yy += hh;
  421.     if (my <= yy || yy>=(Y+H)) return l;
  422.   }
  423.   return 0;
  424. }
  425.  
  426. int Fl_Browser_::select(void* l, int i, int docallbacks) {
  427.   if (type() == FL_MULTI_BROWSER) {
  428.     if (selection_ != l) {
  429.       if (selection_) redraw_line(selection_);
  430.       selection_ = l;
  431.       redraw_line(l);
  432.     }
  433.     if ((!i)==(!item_selected(l))) return 0;
  434.     item_select(l, i);
  435.     redraw_line(l);
  436.   } else {
  437.     if (i && selection_ == l) return 0;
  438.     if (!i && selection_ != l) return 0;
  439.     if (selection_) {
  440.       item_select(selection_, 0);
  441.       redraw_line(selection_);
  442.       selection_ = 0;
  443.     }
  444.     if (i) {
  445.       item_select(l, 1);
  446.       selection_ = l;
  447.       redraw_line(l);
  448.       display(l);
  449.     }
  450.   }        
  451.   Fl::event_clicks(0);
  452.   if (docallbacks) do_callback();
  453.   return 1;
  454. }
  455.  
  456. int Fl_Browser_::deselect(int docallbacks) {
  457.   if (type() == FL_MULTI_BROWSER) {
  458.     int change = 0;
  459.     for (void* p = item_first(); p; p = item_next(p))
  460.       change |= select(p, 0, docallbacks);
  461.     return change;
  462.   } else {
  463.     if (!selection_) return 0;
  464.     item_select(selection_, 0);
  465.     redraw_line(selection_);
  466.     selection_ = 0;
  467.     return 1;
  468.   }
  469. }
  470.  
  471. int Fl_Browser_::select_only(void* l, int docallbacks) {
  472.   if (!l) return deselect(docallbacks);
  473.   int change = 0;
  474.   if (type() == FL_MULTI_BROWSER) {
  475.     for (void* p = item_first(); p; p = item_next(p))
  476.       if (p != l) change |= select(p, 0, docallbacks);
  477.   }
  478.   change |= select(l, 1, docallbacks);
  479.   display(l);
  480.   return change;
  481. }
  482.  
  483. int Fl_Browser_::handle(int event) {
  484.  
  485.   // must do shortcuts first or the scrollbar will get them...
  486.   if (event == FL_SHORTCUT && type() >= FL_HOLD_BROWSER) {
  487.     void* l1 = selection_;
  488.     void* l = l1; if (!l) l = top_; if (!l) l = item_first();
  489.     if (l) {
  490.       if (type()==FL_HOLD_BROWSER) switch (Fl::event_key()) {
  491.       case FL_Down:
  492.     while ((l = item_next(l)))
  493.       if (item_height(l)>0) {select_only(l, 1); break;}
  494.     return 1;
  495.       case FL_Up:
  496.     while ((l = item_prev(l))) if (item_height(l)>0) {
  497.       select_only(l, 1); break;}
  498.     return 1;
  499.       } else switch (Fl::event_key()) {
  500.       case FL_Enter:
  501.     select_only(l, 1);
  502.     return 1;
  503.       case ' ':
  504.     selection_ = l;
  505.     select(l, !item_selected(l), 1);
  506.     return 1;
  507.       case FL_Down:
  508.     while ((l = item_next(l))) {
  509.       if (Fl::event_state(FL_SHIFT|FL_CTRL))
  510.         select(l, l1 ? item_selected(l1) : 1, 1);
  511.       if (item_height(l)>0) goto J1;
  512.     }
  513.     return 1;
  514.       case FL_Up:
  515.     while ((l = item_prev(l))) {
  516.       if (Fl::event_state(FL_SHIFT|FL_CTRL))
  517.         select(l, l1 ? item_selected(l1) : 1, 1);
  518.       if (item_height(l)>0) goto J1;
  519.     }
  520.     return 1;
  521.       J1:
  522.     if (selection_) redraw_line(selection_);
  523.     selection_ = l; redraw_line(l);
  524.     display(l);
  525.     return 1;
  526.       }
  527.     }
  528.   }
  529.  
  530.   if (Fl_Group::handle(event)) return 1;
  531.   int X, Y, W, H; bbox(X, Y, W, H);
  532.   int my;
  533.   static char change;
  534.   static char whichway;
  535.   static int py;
  536.   switch (event) {
  537.   case FL_PUSH:
  538.     if (!Fl::event_inside(X, Y, W, H)) return 0;
  539.     if (type() == FL_SELECT_BROWSER) deselect();
  540.     my = py = Fl::event_y();
  541.     change = 0;
  542.     if (type() == FL_NORMAL_BROWSER || !top_)
  543.       ;
  544.     else if (type() == FL_MULTI_BROWSER) {
  545.       void* l = find_item(my);
  546.       whichway = 1;
  547.       if (Fl::event_state(FL_SHIFT|FL_CTRL)) { // toggle selection:
  548.     if (l) {
  549.       whichway = !item_selected(l);
  550.       change = select(l, whichway, when() & FL_WHEN_CHANGED);
  551.     }
  552.       } else {
  553.     change = select_only(l, when() & FL_WHEN_CHANGED);
  554.       }
  555.     } else {
  556.       change = select_only(find_item(my), when() & FL_WHEN_CHANGED);
  557.     }
  558.     return 1;
  559.   case FL_DRAG:
  560.     // do the scrolling first:
  561.     my = Fl::event_y();
  562.     if (my < Y && my < py) {
  563.       int p = real_position_+my-Y;
  564.       if (p<0) p = 0;
  565.       position(p);
  566.     } else if (my > (Y+H) && my > py) {
  567.       int p = real_position_+my-(Y+H);
  568.       int h = full_height()-H; if (p > h) p = h;
  569.       if (p<0) p = 0;
  570.       position(p);
  571.     }
  572.     if (type() == FL_NORMAL_BROWSER || !top_)
  573.       ;
  574.     else if (type() == FL_MULTI_BROWSER) {
  575.       void* l = find_item(my);
  576.       void* t; void* b; // this will be the range to change
  577.       if (my > py) { // go down
  578.     t = selection_ ? item_next(selection_) : 0;
  579.     b = l ? item_next(l) : 0;
  580.       } else {    // go up
  581.     t = l;
  582.     b = selection_;
  583.       }
  584.       for (; t && t != b; t = item_next(t))
  585.     change |= select(t, whichway, when() & FL_WHEN_CHANGED);
  586.       if (l) selection_ = l;
  587.     } else {
  588.       void* l1 = selection_;
  589.       void* l =
  590.     (Fl::event_x()<x() || Fl::event_x()>x()+w()) ? selection_ :
  591.     find_item(my);
  592.       select_only(l, when() & FL_WHEN_CHANGED);
  593.       change = (l != l1);
  594.     }
  595.     py = my;
  596.     return 1;
  597.   case FL_RELEASE:
  598.     if (type() == FL_SELECT_BROWSER) {
  599.       void* t = selection_; deselect(); selection_ = t;
  600.     }
  601.     if (change) {
  602.       if (when() & FL_WHEN_RELEASE) do_callback();
  603.       else if (!(when()&FL_WHEN_CHANGED)) set_changed();
  604.     } else {
  605.       if (when() & FL_WHEN_NOT_CHANGED) do_callback();
  606.     }
  607.     return 1;
  608.   }
  609.  
  610.   return 0;
  611. }
  612.  
  613. Fl_Browser_::Fl_Browser_(int x, int y, int w, int h, const char* l)
  614.   : Fl_Group(x, y, w, h, l),
  615.     scrollbar(0, 0, 0, 0, 0), // they will be resized by draw()
  616.     hscrollbar(0, 0, 0, 0, 0)
  617. {
  618.   box(FL_NO_BOX);
  619.   align(FL_ALIGN_BOTTOM);
  620.   position_ = real_position_ = 0;
  621.   hposition_ = real_hposition_ = 0;
  622.   offset_ = 0;
  623.   top_ = 0;
  624.   when(FL_WHEN_RELEASE_ALWAYS);
  625.   selection_ = 0;
  626.   color(FL_WHITE);
  627.   selection_color(FL_SELECTION_COLOR);
  628.   scrollbar.callback(scrollbar_callback);
  629. //scrollbar.align(FL_ALIGN_LEFT|FL_ALIGN_BOTTOM); // back compatability?
  630.   hscrollbar.callback(hscrollbar_callback);
  631.   hscrollbar.type(FL_HORIZONTAL);
  632.   textfont_ = FL_HELVETICA;
  633.   textsize_ = FL_NORMAL_SIZE;
  634.   textcolor_ = FL_BLACK;
  635.   has_scrollbar_ = BOTH;
  636.   max_width = 0;
  637.   max_width_item = 0;
  638.   redraw1 = redraw2 = 0;
  639.   end();
  640. }
  641.  
  642. // Default versions of some of the virtual functions:
  643.  
  644. int Fl_Browser_::item_quick_height(void* l) const {
  645.   return item_height(l);
  646. }
  647.  
  648. int Fl_Browser_::incr_height() const {
  649.   return item_quick_height(item_first());
  650. }
  651.  
  652. int Fl_Browser_::full_height() const {
  653.   int t = 0;
  654.   for (void* p = item_first(); p; p = item_next(p))
  655.     t += item_quick_height(p);
  656.   return t;
  657. }
  658.  
  659. int Fl_Browser_::full_width() const {
  660.   return max_width;
  661. }
  662.  
  663. void Fl_Browser_::item_select(void*, int) {}
  664.  
  665. int Fl_Browser_::item_selected(void* l) const {return l==selection_;}
  666.  
  667. //
  668. // End of "$Id: Fl_Browser_.cxx,v 1.10.2.3 1999/09/15 15:18:11 mike Exp $".
  669. //
  670.